/*
 *muduo网络库给用于提供了两个类
 * TcpServer ： 用于创建tcp服务器，
 * TcpClient ： 用于创建tcp客户端
 * epoll + 线程池
 * 好处： 能够把网络I/O的代码和业务代码区分开
 *                   只关心： 用户的连接和断开  用户的可读写事件
 */
#include <ctime> // 用于时间处理
#include <functional>
#include <iostream>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpServer.h>
#include <string>

using namespace std;
using namespace muduo;
using namespace muduo::net;

/*
 * 基于muduo网络库开发服务器程序
 *1. 组合TcpServer
 *2. 创建EventLoop事件循环对象的指针
 *3. 明确TcpServer构造函数需要什么参数， 输出ChatServer的构造函数
 *4. 在当前服务器类的构造函数中，注册用户连接和断开的回调函数
 *5. 设置服务器端的线程数量
 */

class ChatServer {
public:
  ChatServer(EventLoop *loop,               // 事件循环
             const InetAddress &listenAddr, // IP + Port
             const string &nameArg)         // 服务器的名字
      : server_(loop, listenAddr, nameArg), loop_(loop) {
    // 给服务器注册用户连接的创建和断开回调
    server_.setConnectionCallback(
        std::bind(&ChatServer::onConnection, this, std::placeholders::_1));
    // 给服务器注册用户读写事件回调
    server_.setMessageCallback(
        std::bind(&ChatServer::onMessage, this, std::placeholders::_1,
                  std::placeholders::_2, std::placeholders::_3));

    // 设置服务器端的线程数量  1个I/O线程   3个worker线程
    server_.setThreadNum(4);
  }
  //   开启事件循环
  void start() { server_.start(); }

private:

  TcpServer server_; // #1
  EventLoop *loop_;  // # 2

  // 专门处理用户的连接和断开   conn是用户的连接
  // 需要的是用户的连接和断开事件回调
  void onConnection(const TcpConnectionPtr &conn) {
    if (conn->connected()) {
      cout << conn->peerAddress().toIpPort() << "->"
           << conn->localAddress().toIpPort() << "state:online" << endl;
    } else {
      cout << conn->peerAddress().toIpPort() << "->"
           << conn->localAddress().toIpPort() << "state:offline" << endl;
    }
  }

  // 专门处理用户的可读写事件   conn是用户的连接  需要的是用户的可读写事件回调
  void onMessage(const TcpConnectionPtr &conn, // 用户的连接
                 Buffer *buf,                  // 缓冲区
                 Timestamp time)               // 接受到数据的时间信息
  {
    // 打印用户发送的信息
    string msg = buf->retrieveAllAsString();
    // 将time转为字符串并格式化
    char timeStr[32];
    time_t seconds = time.secondsSinceEpoch();
    struct tm *tm_time = localtime(&seconds);
    strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", tm_time);
    cout << "recv data:" << msg << " time:" << timeStr << endl;
    // 给用户发送数据 回显
    conn->send(msg);
  }

};

int main() {
  EventLoop loop;//epoll
  InetAddress addr("0.0.0.0", 6000);
  ChatServer server(&loop, addr, "ChatServer");
  server.start();
  loop.loop();
  return 0;
}